package org.hackystat.sdsa.analyzer.control.compressor;

import java.util.ArrayList;
import java.util.List;

import org.hackystat.sdsa.analyzer.SdsaAnalyzerException;
import org.hackystat.sdsa.analyzer.model.activity.Activity;
import org.hackystat.sdsa.analyzer.model.activity.refactoring.BinaryRefactorActivity;
import org.hackystat.sdsa.analyzer.model.activity.refactoring.RefactorOperator;
import org.hackystat.sdsa.analyzer.model.activity.refactoring.RefactorSubjectType;
import org.hackystat.sdsa.analyzer.model.activity.refactoring.UnaryRefactorActivity;

/**
 * Implements the algorithm to compress refactoring activities.
 * 
 * @author hongbing
 *
 */
public class RefactoringCompressor implements Compressor {

  /**
   * Compress the refactoring activities. For instance, the following 
   * three refactoring actions can be combined together as add method refactoring action.
   * 
   * Before: 
   *   TestStack.java REFACTOR ADD FIELD {void set}
   *   TestStack.java REFACTOR RENAME FIELD {set -> void setUp}
   *   TestStack.java REFACTOR RENAME METHOD {setUp -> void setUp()}
   *   
   * After:  
   *   TestStack.java REFACTOR ADD METHOD {void setUp()}
   * 
   * @param activityList Activity list.
   * @throws SdsaAnalyzerException If problem occurs.
   */
  public void compress(List<Activity> activityList) throws SdsaAnalyzerException {
    RefactorOperator ADD = RefactorOperator.getInstance("ADD");
    RefactorOperator RENAME = RefactorOperator.getInstance("RENAME");
    
    RefactorSubjectType FIELD = RefactorSubjectType.getInstance("FIELD");
    RefactorSubjectType METHOD = RefactorSubjectType.getInstance("METHOD");
    
    List<Activity> activityListCopy = new ArrayList<Activity>();
    for (int i = 0; i < activityList.size(); i++) {
      Activity activity = activityList.get(i);
      
      if (activityList.get(i) instanceof UnaryRefactorActivity) {
        UnaryRefactorActivity unaryRefactor = (UnaryRefactorActivity) activity;
        if (unaryRefactor.getOperator() == ADD) {
          int j = i + 1;
          
          String lastSubjectName = unaryRefactor.getSubjectName();
          while (j < activityList.size()) {
            Activity nextActivity = activityList.get(j); 
            if (nextActivity instanceof BinaryRefactorActivity) {
              BinaryRefactorActivity nextBinaryRefactor = (BinaryRefactorActivity) nextActivity;
              if (nextBinaryRefactor.getOperator() == RENAME &&
                  (nextBinaryRefactor.getSubjectType() == FIELD ||
                   nextBinaryRefactor.getSubjectType() == METHOD) &&
                   lastSubjectName.endsWith(nextBinaryRefactor.getFromSubject())) {
                lastSubjectName = nextBinaryRefactor.getToSubject();
                j++;
              }
              else {
                break;
              }
            }
            else {
              break;
            }
          }
          
          if (j > i + 1) {
            BinaryRefactorActivity lastRefactor = (BinaryRefactorActivity) activityList.get(j - 1);
            unaryRefactor.setSubjectType(lastRefactor.getSubjectType());
            unaryRefactor.setSubjectName(lastRefactor.getToSubject());
            i = j - 1;
          }
        }
      } 
      
      activityListCopy.add(activity);
    }

    activityList.clear();
    activityList.addAll(activityListCopy);
  }

}
